1 Goal of the Lecture

  • Get familiar with plotly
  • Discuss options for interactive plots
  • Get familiar with plotly syntax

2 What is plotly

Plotly website: “plotly is an R package for creating interactive web-based graphs via the open source JavaScript graphing library plotly.js.”

We are going to explore plotly as a ggplot2 extension that will allow as to create interactive plots from ggplot2 objects.

3 Why plotly

Plotly is one the most popular library to create interactive plots for its extensive maintenance, documentation, and most important, it looks beautiful. However, the top 1 reason is how easy to use is with the adaptation of ggplot2.

4 How to install plotly

# From CRAN
install.packages("plotly")

# From github
devtools::install_github("ropensci/plotly")

5 ggplotly()

5.1 Description

This function converts a ggplot2::ggplot() object to a plotly object.

ggplotly(
  p = ggplot2::last_plot(),
  width = NULL,
  height = NULL,
  tooltip = "all",
  dynamicTicks = FALSE,
  layerData = 1,
  originalData = TRUE,
  source = "A",
  ...
)

5.2 Examples

Now, we are going to explore multiple examples of the integration between ggplot2 and plotly with the parsing function ggplotly()

5.3 Scatter plots

# Tip: Always load libraries at the beginning of the markdown documetns

library(tidyverse)
library(plotly)
library(ggsci)

5.3.1 Penguins

ggpenguins <- palmerpenguins::penguins %>% 
  ggplot(aes( bill_length_mm , body_mass_g, color = species )) + 
  geom_point() + 
  scale_color_d3() + 
  theme_bw()

ggpenguins

Things you have can do with an interactive plot

  • Zoom in
  • Zoom out
  • Turn off groups (click on the legend)
  • Download plot as png
ggplotly(ggpenguins)

5.3.2 PCA

# Library here just to make emphasis 
library(ggfortify)

In this case we are going to explore a new library ggfortify that accepts prcomp results and creates an automatic scores PCA plot.

After you perform PCA analysis, you can use autorplot() to create a ggplot2 object for using in the ggplotly() function.

df <- iris[1:4] # Extractict numeric variables
pca_res <- prcomp(df, scale. = TRUE) # Making PCA
p <- autoplot(pca_res, data = iris, colour = 'Species') + # PCA autoplot
  scale_color_d3()
ggplotly(p)

5.4 Distribution plots

5.4.1 Boxplots

midwest: census data

percollege: Percent college educated

boxplot <- ggplot(midwest, aes(state, percollege, color = state) ) + 
  geom_boxplot() +
  scale_color_d3() +
  theme_bw() + 
  coord_flip()

ggplotly(boxplot)

5.4.2 Density plots

density <- ggplot(diamonds, aes(x = price)) + 
  geom_density(aes(fill = "epanechnikov"), kernel = "epanechnikov") + 
  facet_grid(~cut) + 
  ggtitle("Kernel density estimate with Facets")

ggplotly(density)

5.4.3 Barplots

stack_barplot <- ggplot(mpg, aes(class))   + 
  geom_bar(aes(fill = drv)) + scale_fill_d3() + theme_bw()

ggplotly(stack_barplot)

5.5 Hover label aesthetics

5.5.1 Tooltip

Toltip is an argument that controls the text that is shown when you hover the mouse over the data. By default, all mapping variables are shown. You can modify the order and the variables that are shown in the tooltip.

In the penguins data we have more variables that may want to include in the text shown in our plotly plot such as sex and island.

# dt[seq(10),] subset the ten first row and then use glimpse to shorten the output
glimpse(palmerpenguins::penguins[seq(10), ]) 
## Rows: 10
## Columns: 8
## $ species           <fct> Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adel…
## $ island            <fct> Torgersen, Torgersen, Torgersen, Torgersen, Torgerse…
## $ bill_length_mm    <dbl> 39.1, 39.5, 40.3, NA, 36.7, 39.3, 38.9, 39.2, 34.1, …
## $ bill_depth_mm     <dbl> 18.7, 17.4, 18.0, NA, 19.3, 20.6, 17.8, 19.6, 18.1, …
## $ flipper_length_mm <int> 181, 186, 195, NA, 193, 190, 181, 195, 193, 190
## $ body_mass_g       <int> 3750, 3800, 3250, NA, 3450, 3650, 3625, 4675, 3475, …
## $ sex               <fct> male, female, female, NA, female, male, female, male…
## $ year              <int> 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007…
ggplotly(ggpenguins)

“colour” is requiered and “color” is not supported

ggplotly(ggpenguins,
         tooltip = c("colour") )

5.6 Hovel label aesthetis

You might not like the default hover text aesthetics, and can change them! You can do this using style and layout and adding these functions using the pipe %>%.

Code taken from BioDash

# setting fonts for the plot
font <- list(
  family = "Courier New",
  size = 15,
  color = "white")

# setting hover label specs
label <- list(
  bgcolor = "#3d1b40",
  bordercolor = "transparent",
  font = font) # we can do this bc we already set font

# amending our ggplotly call to include new fonts and hover label specs
ggplotly(ggpenguins, tooltip = "colour") %>%
  style(hoverlabel = label) %>%
  layout(font = font)

5.7 Saving ggplotly() objects

After you have done an amazing job creating a beautiful ggplot and made it interactive, you might want to save in a file. Here, you have two options, create a markdown and knit your interactive plot in a html file, if you knit in a static file such as pdf or word file, you will lose the interactive part of your plot.

You will need to assign the interactive plot to an object, and then, export or save your plot to an html file.

# assign ggplotly plot to an object
ggplotly_to_save <- ggplotly(ggpenguins, tooltip = "colour") %>%
  style(hoverlabel = label) %>%
  layout(font = font)

# save
saveWidget(widget = ggplotly_to_save,
           file = "ggplotlying.html")
LS0tCnRpdGxlOiAiSW50ZXJhY3RpdmUgcGxvdCB3aXRoIFBsb3RseSIKYXV0aG9yOiAiRGFuaWVsIFF1aXJveiIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogNAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRoZW1lOiBmbGF0bHkKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tCgojIEdvYWwgb2YgdGhlIExlY3R1cmUKCiogR2V0IGZhbWlsaWFyIHdpdGggcGxvdGx5CiogRGlzY3VzcyBvcHRpb25zIGZvciBpbnRlcmFjdGl2ZSBwbG90cwoqIEdldCBmYW1pbGlhciB3aXRoIHBsb3RseSBzeW50YXgKCgojIFdoYXQgaXMgcGxvdGx5CgpbUGxvdGx5IHdlYnNpdGU6XShodHRwczovL3Bsb3RseS5jb20vci9nZXR0aW5nLXN0YXJ0ZWQvKQoicGxvdGx5IGlzIGFuIFIgcGFja2FnZSBmb3IgY3JlYXRpbmcgaW50ZXJhY3RpdmUgd2ViLWJhc2VkIGdyYXBocyB2aWEgdGhlCm9wZW4gc291cmNlIEphdmFTY3JpcHQgZ3JhcGhpbmcgbGlicmFyeSBwbG90bHkuanMuIgoKCldlIGFyZSBnb2luZyB0byBleHBsb3JlIGBwbG90bHlgIGFzIGEgYGdncGxvdDJgIGV4dGVuc2lvbiB0aGF0IHdpbGwgYWxsb3cgYXMKdG8gY3JlYXRlIGludGVyYWN0aXZlIHBsb3RzIGZyb20gZ2dwbG90MiBvYmplY3RzLgoKYGBge3IgZWNobz1GQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImltZy9QbG90bHktbG9nby5wbmciKQpgYGAKCgoKIyBXaHkgcGxvdGx5CgpQbG90bHkgaXMgb25lIHRoZSBtb3N0IHBvcHVsYXIgbGlicmFyeSB0byBjcmVhdGUgaW50ZXJhY3RpdmUgcGxvdHMgZm9yIGl0cyAKZXh0ZW5zaXZlIG1haW50ZW5hbmNlLCBkb2N1bWVudGF0aW9uLCBhbmQgbW9zdCBpbXBvcnRhbnQsIGl0IGxvb2tzIGJlYXV0aWZ1bC4KSG93ZXZlciwgdGhlIHRvcCAxIHJlYXNvbiBpcyBob3cgZWFzeSB0byB1c2UgaXMgd2l0aCB0aGUgYWRhcHRhdGlvbiBvZiBnZ3Bsb3QyLgoKIyBIb3cgdG8gaW5zdGFsbCBwbG90bHkKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0KIyBGcm9tIENSQU4KaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikKCiMgRnJvbSBnaXRodWIKZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJyb3BlbnNjaS9wbG90bHkiKQpgYGAKCgojIGdncGxvdGx5KCkKCmBgYHtyIGVjaG89RkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJpbWcvZ2dwbG90bHkucG5nIikKYGBgCgojIyBEZXNjcmlwdGlvbgoKVGhpcyBmdW5jdGlvbiBjb252ZXJ0cyBhIGBnZ3Bsb3QyOjpnZ3Bsb3QoKWAgb2JqZWN0IHRvIGEgcGxvdGx5IG9iamVjdC4KCmBgYHIKZ2dwbG90bHkoCiAgcCA9IGdncGxvdDI6Omxhc3RfcGxvdCgpLAogIHdpZHRoID0gTlVMTCwKICBoZWlnaHQgPSBOVUxMLAogIHRvb2x0aXAgPSAiYWxsIiwKICBkeW5hbWljVGlja3MgPSBGQUxTRSwKICBsYXllckRhdGEgPSAxLAogIG9yaWdpbmFsRGF0YSA9IFRSVUUsCiAgc291cmNlID0gIkEiLAogIC4uLgopCmBgYAoKCiMjIEV4YW1wbGVzCgoKTm93LCB3ZSBhcmUgZ29pbmcgdG8gZXhwbG9yZSBtdWx0aXBsZSBleGFtcGxlcyBvZiB0aGUgaW50ZWdyYXRpb24gYmV0d2VlbgpnZ3Bsb3QyIGFuZCBwbG90bHkgd2l0aCB0aGUgcGFyc2luZyBmdW5jdGlvbiAKW2BnZ3Bsb3RseSgpYF0oaHR0cHM6Ly93d3cucmRvY3VtZW50YXRpb24ub3JnL3BhY2thZ2VzL3Bsb3RseS92ZXJzaW9ucy80LjEwLjAvdG9waWNzL2dncGxvdGx5KQoKIyMgU2NhdHRlciBwbG90cwoKCgpgYGB7ciBsb2RpbmcgbGlicmFyaWVzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0KIyBUaXA6IEFsd2F5cyBsb2FkIGxpYnJhcmllcyBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBtYXJrZG93biBkb2N1bWV0bnMKCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShnZ3NjaSkKCmBgYAoKCiMjIyBQZW5ndWlucwoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQpnZ3Blbmd1aW5zIDwtIHBhbG1lcnBlbmd1aW5zOjpwZW5ndWlucyAlPiUgCiAgZ2dwbG90KGFlcyggYmlsbF9sZW5ndGhfbW0gLCBib2R5X21hc3NfZywgY29sb3IgPSBzcGVjaWVzICkpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgc2NhbGVfY29sb3JfZDMoKSArIAogIHRoZW1lX2J3KCkKCmdncGVuZ3VpbnMKYGBgCgoKClRoaW5ncyB5b3UgaGF2ZSBjYW4gZG8gd2l0aCBhbiBpbnRlcmFjdGl2ZSBwbG90CgoqIFpvb20gaW4KKiBab29tIG91dAoqIFR1cm4gb2ZmIGdyb3VwcyAoY2xpY2sgb24gdGhlIGxlZ2VuZCkKKiBEb3dubG9hZCBwbG90IGFzIHBuZwoKYGBge3IgZ2dwbG90bHkgc2NhdHRlcn0KZ2dwbG90bHkoZ2dwZW5ndWlucykKYGBgCgoKIyMjIFBDQQoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0V9CiMgTGlicmFyeSBoZXJlIGp1c3QgdG8gbWFrZSBlbXBoYXNpcyAKbGlicmFyeShnZ2ZvcnRpZnkpCmBgYAoKCkluIHRoaXMgY2FzZSB3ZSBhcmUgZ29pbmcgdG8gZXhwbG9yZSBhIG5ldyBsaWJyYXJ5IGBnZ2ZvcnRpZnlgIHRoYXQgYWNjZXB0cwpgcHJjb21wYCByZXN1bHRzIGFuZCBjcmVhdGVzIGFuIGF1dG9tYXRpYyBzY29yZXMgUENBIHBsb3QuCgpBZnRlciB5b3UgcGVyZm9ybSBQQ0EgYW5hbHlzaXMsIHlvdSBjYW4gdXNlIGBhdXRvcnBsb3QoKWAgdG8gY3JlYXRlIGEgZ2dwbG90MiAKb2JqZWN0IGZvciB1c2luZyBpbiB0aGUgYGdncGxvdGx5KClgIGZ1bmN0aW9uLgoKYGBge3J9CmRmIDwtIGlyaXNbMTo0XSAjIEV4dHJhY3RpY3QgbnVtZXJpYyB2YXJpYWJsZXMKcGNhX3JlcyA8LSBwcmNvbXAoZGYsIHNjYWxlLiA9IFRSVUUpICMgTWFraW5nIFBDQQpwIDwtIGF1dG9wbG90KHBjYV9yZXMsIGRhdGEgPSBpcmlzLCBjb2xvdXIgPSAnU3BlY2llcycpICsgIyBQQ0EgYXV0b3Bsb3QKICBzY2FsZV9jb2xvcl9kMygpCmdncGxvdGx5KHApCmBgYAoKCiMjIERpc3RyaWJ1dGlvbiBwbG90cwoKIyMjIEJveHBsb3RzCgptaWR3ZXN0OiBjZW5zdXMgZGF0YQoKcGVyY29sbGVnZTogUGVyY2VudCBjb2xsZWdlIGVkdWNhdGVkCgpgYGB7cn0KYm94cGxvdCA8LSBnZ3Bsb3QobWlkd2VzdCwgYWVzKHN0YXRlLCBwZXJjb2xsZWdlLCBjb2xvciA9IHN0YXRlKSApICsgCiAgZ2VvbV9ib3hwbG90KCkgKwogIHNjYWxlX2NvbG9yX2QzKCkgKwogIHRoZW1lX2J3KCkgKyAKICBjb29yZF9mbGlwKCkKCmdncGxvdGx5KGJveHBsb3QpCmBgYAoKIyMjIERlbnNpdHkgcGxvdHMKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQpkZW5zaXR5IDwtIGdncGxvdChkaWFtb25kcywgYWVzKHggPSBwcmljZSkpICsgCiAgZ2VvbV9kZW5zaXR5KGFlcyhmaWxsID0gImVwYW5lY2huaWtvdiIpLCBrZXJuZWwgPSAiZXBhbmVjaG5pa292IikgKyAKICBmYWNldF9ncmlkKH5jdXQpICsgCiAgZ2d0aXRsZSgiS2VybmVsIGRlbnNpdHkgZXN0aW1hdGUgd2l0aCBGYWNldHMiKQoKZ2dwbG90bHkoZGVuc2l0eSkKYGBgCgojIyMgQmFycGxvdHMKCgpgYGB7cn0KCnN0YWNrX2JhcnBsb3QgPC0gZ2dwbG90KG1wZywgYWVzKGNsYXNzKSkgICArIAogIGdlb21fYmFyKGFlcyhmaWxsID0gZHJ2KSkgKyBzY2FsZV9maWxsX2QzKCkgKyB0aGVtZV9idygpCgpnZ3Bsb3RseShzdGFja19iYXJwbG90KQpgYGAKCgojIyBIb3ZlciBsYWJlbCBhZXN0aGV0aWNzCgojIyMgVG9vbHRpcAoKVG9sdGlwIGlzIGFuIGFyZ3VtZW50IHRoYXQgY29udHJvbHMgdGhlIHRleHQgdGhhdCBpcyBzaG93biB3aGVuIHlvdSBob3ZlciAKdGhlIG1vdXNlIG92ZXIgdGhlIGRhdGEuIEJ5IGRlZmF1bHQsIGFsbCBtYXBwaW5nIHZhcmlhYmxlcyBhcmUgc2hvd24uIFlvdSBjYW4gCm1vZGlmeSB0aGUgb3JkZXIgYW5kIHRoZSB2YXJpYWJsZXMgdGhhdCBhcmUgc2hvd24gaW4gdGhlIHRvb2x0aXAuCgpJbiB0aGUgcGVuZ3VpbnMgZGF0YSB3ZSBoYXZlIG1vcmUgdmFyaWFibGVzIHRoYXQgbWF5IHdhbnQgdG8gaW5jbHVkZSBpbiB0aGUKdGV4dCBzaG93biBpbiBvdXIgcGxvdGx5IHBsb3Qgc3VjaCBhcyBzZXggYW5kIGlzbGFuZC4gCgpgYGB7cn0KIyBkdFtzZXEoMTApLF0gc3Vic2V0IHRoZSB0ZW4gZmlyc3Qgcm93IGFuZCB0aGVuIHVzZSBnbGltcHNlIHRvIHNob3J0ZW4gdGhlIG91dHB1dApnbGltcHNlKHBhbG1lcnBlbmd1aW5zOjpwZW5ndWluc1tzZXEoMTApLCBdKSAKYGBgCgpgYGB7cn0KZ2dwbG90bHkoZ2dwZW5ndWlucykKYGBgCgoKPiAiY29sb3VyIiBpcyByZXF1aWVyZWQgYW5kICJjb2xvciIgaXMgbm90IHN1cHBvcnRlZAoKYGBge3J9CmdncGxvdGx5KGdncGVuZ3VpbnMsCiAgICAgICAgIHRvb2x0aXAgPSBjKCJjb2xvdXIiKSApCmBgYAoKCiMjIEhvdmVsIGxhYmVsIGFlc3RoZXRpcwoKWW91IG1pZ2h0IG5vdCBsaWtlIHRoZSBkZWZhdWx0IGhvdmVyIHRleHQgYWVzdGhldGljcywgYW5kIGNhbiBjaGFuZ2UgdGhlbSEKWW91IGNhbiBkbyB0aGlzIHVzaW5nIHN0eWxlIGFuZCBsYXlvdXQgYW5kIGFkZGluZyB0aGVzZQpmdW5jdGlvbnMgdXNpbmcgdGhlIHBpcGUgJT4lLgoKQ29kZSB0YWtlbiBmcm9tIFtCaW9EYXNoXShodHRwczovL2Jpb2Rhc2guZ2l0aHViLmlvL2NvZGVjbHViL3MwMmUxMl9wbG90bHkvKQoKYGBge3J9CiMgc2V0dGluZyBmb250cyBmb3IgdGhlIHBsb3QKZm9udCA8LSBsaXN0KAogIGZhbWlseSA9ICJDb3VyaWVyIE5ldyIsCiAgc2l6ZSA9IDE1LAogIGNvbG9yID0gIndoaXRlIikKCiMgc2V0dGluZyBob3ZlciBsYWJlbCBzcGVjcwpsYWJlbCA8LSBsaXN0KAogIGJnY29sb3IgPSAiIzNkMWI0MCIsCiAgYm9yZGVyY29sb3IgPSAidHJhbnNwYXJlbnQiLAogIGZvbnQgPSBmb250KSAjIHdlIGNhbiBkbyB0aGlzIGJjIHdlIGFscmVhZHkgc2V0IGZvbnQKCiMgYW1lbmRpbmcgb3VyIGdncGxvdGx5IGNhbGwgdG8gaW5jbHVkZSBuZXcgZm9udHMgYW5kIGhvdmVyIGxhYmVsIHNwZWNzCmdncGxvdGx5KGdncGVuZ3VpbnMsIHRvb2x0aXAgPSAiY29sb3VyIikgJT4lCiAgc3R5bGUoaG92ZXJsYWJlbCA9IGxhYmVsKSAlPiUKICBsYXlvdXQoZm9udCA9IGZvbnQpCmBgYAoKCiMjIFNhdmluZyBnZ3Bsb3RseSgpIG9iamVjdHMKCkFmdGVyIHlvdSBoYXZlIGRvbmUgYW4gYW1hemluZyBqb2IgY3JlYXRpbmcgYSBiZWF1dGlmdWwgZ2dwbG90IGFuZCBtYWRlIGl0IAppbnRlcmFjdGl2ZSwgeW91IG1pZ2h0IHdhbnQgdG8gc2F2ZSBpbiBhIGZpbGUuIEhlcmUsIHlvdSBoYXZlIHR3byBvcHRpb25zLCAKY3JlYXRlIGEgbWFya2Rvd24gYW5kIGtuaXQgeW91ciBpbnRlcmFjdGl2ZSBwbG90IGluIGEgKmh0bWwqIGZpbGUsCmlmIHlvdSBrbml0IGluIGEgc3RhdGljIGZpbGUgc3VjaCBhcyBwZGYgb3Igd29yZCBmaWxlLCB5b3Ugd2lsbCBsb3NlCnRoZSBpbnRlcmFjdGl2ZSBwYXJ0IG9mIHlvdXIgcGxvdC4KCllvdSB3aWxsIG5lZWQgdG8gYXNzaWduIHRoZSBpbnRlcmFjdGl2ZSBwbG90IHRvIGFuIG9iamVjdCwgYW5kIHRoZW4sIGV4cG9ydApvciBzYXZlIHlvdXIgcGxvdCB0byBhbiAqaHRtbCogZmlsZS4KCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0KIyBhc3NpZ24gZ2dwbG90bHkgcGxvdCB0byBhbiBvYmplY3QKZ2dwbG90bHlfdG9fc2F2ZSA8LSBnZ3Bsb3RseShnZ3Blbmd1aW5zLCB0b29sdGlwID0gImNvbG91ciIpICU+JQogIHN0eWxlKGhvdmVybGFiZWwgPSBsYWJlbCkgJT4lCiAgbGF5b3V0KGZvbnQgPSBmb250KQoKIyBzYXZlCnNhdmVXaWRnZXQod2lkZ2V0ID0gZ2dwbG90bHlfdG9fc2F2ZSwKICAgICAgICAgICBmaWxlID0gImdncGxvdGx5aW5nLmh0bWwiKQpgYGAKCgoKCg==